"""Video metadata models and normalization utilities for DYVA.

- Follows project rules: PEP8, type annotations, logging, docstrings.
- Provides unit normalization for Chinese units (e.g., 万), duration parsing, and category mapping.
"""
from __future__ import annotations

from dataclasses import dataclass, field
from typing import List, Optional, Dict, Any
import re


DURATION_CATEGORY_NAMES = {
    "le_15s": "≤15秒",
    "le_60s": "≤1分钟",
    "le_300s": "≤5分钟",
    "gt_300s": "＞5分钟",
}


@dataclass
class Engagement:
    likes: Optional[int] = None
    comments: Optional[int] = None
    favorites: Optional[int] = None
    shares: Optional[int] = None


@dataclass
class VideoMetadata:
    author: str
    publish_time: str
    original_title: str
    processed_title: str
    topics: List[str]
    video_url: str
    video_id: str
    duration_seconds: Optional[int]
    duration_category: str
    engagement: Engagement = field(default_factory=Engagement)
    copy_name: str = ""
    video_type: str = "NA"

    def to_csv_row(self) -> Dict[str, Any]:
        """Return a CSV-ready row mapping consistent with config columns."""
        return {
            "author": self.author,
            "publish_time": self.publish_time,
            "original_title": self.original_title,
            "processed_title": self.processed_title,
            "topics": ",".join(self.topics),
            "video_url": self.video_url,
            "video_id": self.video_id,
            "duration_seconds": self.duration_seconds if self.duration_seconds is not None else "NA",
            "duration_category": self.duration_category,
            "likes": self.engagement.likes,
            "comments": self.engagement.comments,
            "favorites": self.engagement.favorites,
            "shares": self.engagement.shares,
            "copy_name": self.copy_name,
            # 分类结果占位（由文本/视觉分析器补充）
            "theme": "NA",
            "sentiment": "NA",
            "style": "NA",
            "title_emotion": "NA",
            "title_topic": "NA",
            "actor": "NA",
            "symbols": "NA",
        }


def normalize_cn_unit(value: str | int | float | None) -> Optional[int]:
    """Normalize Chinese numeric units to integer.

    - Supports values like '95.2万', '100', '  3.5 万  '.
    - Returns None on invalid input.
    """
    if value is None:
        return None
    if isinstance(value, (int, float)):
        return int(value)
    s = str(value).strip()
    if not s or s.lower() == "na":
        return None
    # Remove commas and spaces
    s = s.replace(",", "")
    # Match decimal or integer with optional '万'
    m = re.fullmatch(r"([0-9]+(?:\.[0-9]+)?)\s*(万)?", s)
    if not m:
        # If it's a pure integer (after strip), attempt int
        try:
            return int(s)
        except Exception:
            return None
    num = float(m.group(1))
    unit = m.group(2)
    if unit == "万":
        num *= 10000
    return int(num)


def parse_duration_str(s: str) -> Optional[int]:
    """Parse 'MM:SS' duration string into seconds.

    Returns None if not parsable.
    """
    if not s:
        return None
    s = s.strip()
    m = re.fullmatch(r"([0-9]{1,2}):([0-9]{2})", s)
    if not m:
        return None
    minutes = int(m.group(1))
    seconds = int(m.group(2))
    return minutes * 60 + seconds


def categorize_duration(seconds: Optional[int]) -> str:
    """Map seconds to duration category (Chinese labels)."""
    if seconds is None:
        return "NA"
    if seconds <= 15:
        return DURATION_CATEGORY_NAMES["le_15s"]
    if seconds <= 60:
        return DURATION_CATEGORY_NAMES["le_60s"]
    if seconds <= 300:
        return DURATION_CATEGORY_NAMES["le_300s"]
    return DURATION_CATEGORY_NAMES["gt_300s"]


def make_copy_name(video_id: str) -> str:
    """Return copy name base without extension: 'VID_{video_id}'"""
    return f"VID_{video_id}"

# New: build author+date key and copy name based on Excel fields

def _sanitize_component(s: str) -> str:
    if not s:
        return "NA"
    # Replace forbidden characters for filenames and trim
    s = s.strip()
    return re.sub(r"[\\/:*?\"<>|]", "_", s)


def build_author_date_key(author: str, publish_time: str) -> str:
    """Return '{author}+{YYYY-MM-DD}' using sanitized components.

    - If publish_time includes time, only keep date part.
    - Returns 'NA+NA' when inputs are missing.
    """
    author_s = _sanitize_component(author or "NA")
    pub = (publish_time or "NA").strip()
    date_part = pub.split(" ")[0] if pub and pub != "NA" else "NA"
    date_s = _sanitize_component(date_part)
    return f"{author_s}+{date_s}"


def make_copy_name_author_date(author: str, publish_time: str) -> str:
    """Return 'VID_{author+YYYY-MM-DD}' copy name base without extension."""
    return f"VID_{build_author_date_key(author, publish_time)}"